package com.sky.service.user.impl;

import com.alibaba.fastjson.JSON;
import com.sky.exception.MerchantNotFoundException;
import com.sky.mapper.common.CourierMapper;
import com.sky.mapper.common.MerchantMapper;
import com.sky.mapper.common.OrderMapper;
import com.sky.mapper.common.TradeOrderMapper;
import com.sky.pojo.Courier;
import com.sky.pojo.CourierTradeOrder;
import com.sky.pojo.Merchant;
import com.sky.pojo.Orders;
import com.sky.service.user.OrderDispatchService;
import com.sky.utils.MapUtils;
import com.sky.websocket.WebSocketServer;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
@Transactional(readOnly = true)
public class OrderDispatchServiceImpl implements OrderDispatchService {

    @Autowired
    private MerchantMapper merchantMapper;

    @Autowired
    private CourierMapper courierMapper;

    @Autowired
    private TradeOrderMapper tradeOrderMapper;

    @Autowired
    private WebSocketServer webSocketServer;

    @Autowired
    private OrderMapper orderMapper;

    /**
     * 根据订单的商家位置选择一个骑手
     *
     * @param orders
     * @return
     */
    @Override
    @Transactional(readOnly = false)
    public Courier dispatchCourier(Orders orders, String tradeNo, Long courierId) {
        //0. 如果是转单求助 我们需要自己查询订单数据
        if(null == orders && StringUtils.isNotEmpty(tradeNo)){
            orders = orderMapper.selectByTradeNo(tradeNo);
        }

        //1.优先查询商家10公里内的在职骑手  -- 多个骑手
        List<Courier> courierList = findCourierNearMerchant(orders.getShopId());

        if(null != courierList && courierList.size() > 0){
            //0.0 排除当前转单求助的骑手
            courierList = courierList.stream().filter(courier -> !courier.getId().equals(courierId)).collect(Collectors.toList());

            //2.然后考虑上述骑手中，订单量最少的骑手
                //2.1 查询符合要求的骑手的id
            List<Long> idsList = courierList.stream().map(courier -> courier.getId()).collect(Collectors.toList());
            //2.2 通过id分组统计每个骑手的当日接单数量
            String localDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
            List<Map<String,Long>> courierOrderNumList = courierMapper.findTodayCourierOrderNumByCourierId(idsList, localDate);
            //2.3 通过stream流求出当日接单最少的单量
            Long minOrderNum = courierOrderNumList.stream().min(new Comparator<Map<String,Long>>() {
                @Override
                public int compare(Map<String,Long> o1, Map<String,Long>o2) {
                    return o1.get("total").intValue() - o2.get("total").intValue();
                }
            }).get().get("total");
            //3.找出最小订单相近的骑手（3单以内）  -- 比如最小订单数是10，那么找出订单量10,11,12,13的骑手   --多个骑手
            List<Long> idsList2 = courierOrderNumList.stream()
                    .filter(map -> map.get("total") <= minOrderNum + 3)
                    .map(map -> map.get("id"))
                    .collect(Collectors.toList());
            //4.骑手的待接单和已接单（骑手正在进行中的订单）不能超过12
            idsList2 = courierMapper.findCourierOrderingLess12ByIds(idsList2, localDate);
            //5.按照上述规则条件如果没有找到，从最初的10公里内的骑手中随机挑选一个
            if(null == idsList2 || idsList2.size() == 0){
                int index = new Random().nextInt(courierList.size()); //10个骑手 随机能否取到10？[0,10)
                Long id = courierList.stream().map(courier -> courier.getId()).collect(Collectors.toList()).get(index);
                idsList2 = new ArrayList<>();
                idsList2.add(id);
            }
            //6.然后从所有满足条件的骑手中，找到评分最高的做为最终骑手进行派单
            List<Long> finalCoruierIds = idsList2;
            Courier finalCourier = courierList.stream().filter(courier -> finalCoruierIds.contains(courier.getId().intValue()))
                    .sorted(Comparator.comparing(Courier::getScore).reversed()).collect(Collectors.toList()).get(0);

            //7. 生成运单号
            saveTradeOrder(orders,finalCourier, tradeNo);

            //8. 通知骑手接单
            Map<String,Object> map = new HashMap<>();
            map.put("tradeNo",orders.getNumber());
            map.put("code",1);
            map.put("msg","您有新的待接单,请及时查收！");
            String message = JSON.toJSONString(map);
            webSocketServer.sendtoClient(finalCourier.getId().toString(), message);

            return finalCourier;
        }

        return null;
    }

    /**
     * 生成运单数据
     * @param orders
     * @param finalCourier
     */
    private void saveTradeOrder(Orders orders, Courier finalCourier, String tradeNo) {
        //0.0.0 如果是转单求助 无需新增运单数据 只需要把之前的运单的骑手id修改掉即可
        if(StringUtils.isNotEmpty(tradeNo)){
            tradeOrderMapper.updateCourierById(tradeNo, finalCourier.getId());
            return;
        }

        Merchant merchant = merchantMapper.getShopById(orders.getShopId());

        /**
         * - 1 公里内 3元   0.5
         * - 超出1公里部分 少于3公里部分 1元  3-5元  0.6
         * - 超出3公里部分 0.5元  0.7
         */
        BigDecimal courierCost = BigDecimal.valueOf(0);
        //拿到订单的配送费用
        double deliveryFee = orders.getDeliveryFee().doubleValue();
        //根据配送费来算骑手的提升
        if(deliveryFee <= 3){
            courierCost = courierCost.add(BigDecimal.valueOf(1.5));
        }else if(deliveryFee > 3 && deliveryFee <= 5){
            courierCost = courierCost.add(BigDecimal.valueOf(1.5)); //基础配送费
            courierCost = courierCost.add(BigDecimal.valueOf(deliveryFee - 3).multiply(BigDecimal.valueOf(0.6))); //超出1公里部分 少于3公里部分
        }else{
            courierCost = courierCost.add(BigDecimal.valueOf(1.5)); //基础配送费
            courierCost = courierCost.add(BigDecimal.valueOf(1.2)); //超出1公里部分 少于3公里部分
            courierCost = courierCost.add(BigDecimal.valueOf(deliveryFee - 5).multiply(BigDecimal.valueOf(0.7)));
        }

        CourierTradeOrder tradeOrder = CourierTradeOrder.builder()
                .totalAmount(orders.getAmount())
                .courierId(finalCourier.getId())
                .orderNumber(orders.getNumber())
                .waybillStatus(Orders.PAID) //1 ： 待接单
                .tradeCreateTime(LocalDateTime.now())
                .shopAddress(merchant.getShopAddress())
                .remark(orders.getRemark())
                .customerAddress(orders.getAddress())  //客户地址
                .customerExpectedDeliveryTime(orders.getEstimatedDeliveryTime()) //预计送达时间
                .customerName(orders.getConsignee())
                .shopName(merchant.getShopName())
                .telephone(orders.getPhone())
                .toBeMealTime(orders.getMealTime())
                .income(courierCost)
                .build();


        tradeOrderMapper.insert(tradeOrder);
    }

    /**
     * 商家10公里内的在职骑手
     * @param shopId 店铺的id
     * @return
     */
    private List<Courier> findCourierNearMerchant(Long shopId) {
        //1. 通过店铺的id查询店铺的地址
        Merchant merchant = merchantMapper.getShopById(shopId);
        if(null == merchant){
            throw new MerchantNotFoundException("商家不存在");
        }

        //2. 通过地址调用高德地图 把详细地址转换为坐标
        String addressedLnglat = MapUtils.addressToLnglat(merchant.getShopAddress());

        //3. 查询所有在职的骑手信息
        List<Courier> courierList = courierMapper.findAllOnJob();

        //4. 遍历每一个骑手 然后计算骑手到商家的距离 如果小于10公里就收集起来
        List<Courier> list = courierList.stream().filter(courier -> {
            double distance = MapUtils.calculateDistance(addressedLnglat, courier.getCurLocation());

            return distance < 10000;
        }).collect(Collectors.toList());

        //5. 返回符合要求的骑手信息
        return list;
    }
}
